package com.sh.data.engine.domain.normalization.research.themedesign.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.sh.data.engine.common.exception.BusinessException;
import com.sh.data.engine.domain.base.model.PageResult;
import com.sh.data.engine.domain.base.model.UserContext;
import com.sh.data.engine.domain.normalization.modeldesign.model.service.ModelService;
import com.sh.data.engine.domain.normalization.research.themedesign.model.domain.ThemeDomain;
import com.sh.data.engine.domain.normalization.research.themedesign.model.mapper.ThemeDomainMapper;
import com.sh.data.engine.domain.normalization.research.themedesign.model.param.ListThemeParam;
import com.sh.data.engine.domain.normalization.research.themedesign.model.param.MoveThemeParam;
import com.sh.data.engine.domain.normalization.research.themedesign.model.param.ThemeParam;
import com.sh.data.engine.domain.normalization.standard.service.IDictionaryService;
import com.sh.data.engine.domain.workspace.manager.service.UserService;
import com.sh.data.engine.repository.dao.dataasset.entity.TblPropEntity;
import com.sh.data.engine.repository.dao.normalization.research.themedesign.ThemeMapper;
import com.sh.data.engine.repository.dao.normalization.research.themedesign.entity.ThemeEntity;
import com.sh.data.engine.repository.dao.normalization.standard.entity.DictionaryEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author : mingxi.xpb
 * @date : 2022/1/6 18:46
 */
@Service
@Slf4j
public class ThemeService extends ServiceImpl<ThemeMapper, ThemeEntity> {

    @Autowired
    private ThemeMapper themeMapper;

    @Autowired
    private UserService userService;

    @Lazy
    @Autowired
    private ModelService modelService;

    @Lazy
    @Autowired
    private IDictionaryService dictionaryService;

    @Autowired
    private ThemeDomainMapper themeDomainMapper;

    private static final List<ThemeEntity> INITIAL_THEMES = Lists.newArrayList();

    private static final List<ThemeEntity> INITIAL_LEVEL = Lists.newArrayList();

    /**
     * description 保存或编辑主题
     *
     * @author : mingxi.xpb
     * @date : 2022/1/14 11:25
     */
    public ThemeDomain saveTheme(ThemeParam themeParam, Long projectId) {

        if (Objects.equals(0L, themeParam.getPid())) {
            throw new BusinessException("禁止操作系统层级");
        }

        final String userId = UserContext.getUserId();

        Long themeId = themeParam.getThemeId();
        Long pid = themeParam.getPid();

        ThemeEntity themeEntity =
            ThemeEntity.builder()
                .pid(themeParam.getPid())
                .themeDesc(themeParam.getThemeDesc())
                .themeName(themeParam.getThemeName())
                .projectId(projectId)
                .build();
        ThemeDomain result = new ThemeDomain();
        if (null != themeId) { // 编辑
            ThemeEntity byId = themeMapper.selectById(themeId);
            if (!byId.getPid().equals(pid)) {
                throw new BusinessException("暂不支持调整主题目录");
            }

            isThemeNameExist(
                themeParam.getThemeId(), themeParam.getPid(), themeParam.getThemeName(), projectId);

            themeEntity.setId(themeParam.getThemeId());
            themeEntity.setUpdaterId(userId);
//            LogContext.put(LogKey.NAME.getKey(), themeParam.getThemeName());
//            LogContext.put(LogKey.ISUPDATE.getKey(), LogKey.ISUPDATE.getValue());
            this.themeMapper.updateById(themeEntity);
            result = themeDomainMapper.map(themeEntity);
        } else { // 新增
            boolean flag = validateLevels(pid);
            if (!flag) {
                throw new BusinessException("主题结构不能超过5级");
            }

            isThemeNameExist(null, themeParam.getPid(), themeParam.getThemeName(), projectId);
            themeEntity.setCreatorId(userId);

//            LogContext.put(LogKey.NAME.getKey(), themeParam.getThemeName());
            themeMapper.insert(themeEntity);

//            ConvertUtils.copyProperties(themeEntity, ThemeDomain.class);

            themeId = themeEntity.getId();
            themeParam.setThemeId(themeId);
        }
        return result;
    }

    /**
     * description 删除主题
     *
     * @author : mingxi.xpb
     * @date : 2022/1/14 11:25
     */
    public void deleteTheme(Long themeId, Long projectId) {
        ThemeEntity themeEntityById = themeMapper.selectById(themeId);
        if (themeEntityById == null) {
            log.error("theme is not exist");
            throw new BusinessException("该主题不存在");
        }
        if (Objects.equals(0L, themeEntityById.getPid())) {
            throw new BusinessException("禁止操作系统层级");
        }

        List<ThemeEntity> themeEntities =
            themeMapper.selectList(
                new LambdaQueryWrapper<ThemeEntity>().eq(ThemeEntity::getPid, themeId));
        ;
        if (themeEntities.size() != 0) {
            throw new BusinessException("该主题存在子主题，无法删除");
        }

        List<TblPropEntity> modelByThemeId = modelService.getAllModelByThemeId(themeId);
        if (modelByThemeId.size() != 0) {
            throw new BusinessException("该主题被模型引用，无法删除");
        }

        List<DictionaryEntity> dictionaryByThemeIdList =
            dictionaryService.getDictionaryByThemeId(themeId);
        if (dictionaryByThemeIdList.size() != 0) {
            throw new BusinessException("该主题被标准设计引用，无法删除");
        }

        try {

            themeMapper.deleteById(themeId);
        } catch (Exception e) {
            throw new BusinessException(e.getMessage());
        }
    }

    /**
     * description 查询主题列表，分页查询，仅查询属于某个项目id & pid下的主题
     *
     * @author : mingxi.xpb
     * @date : 2022/1/14 11:25
     */
    public PageResult<ThemeDomain> listThemes(ListThemeParam listThemeParam, Long projectId) {
        Long pid = listThemeParam.getPid();

        LambdaQueryWrapper<ThemeEntity> wrapper =
            new LambdaQueryWrapper<ThemeEntity>().eq(ThemeEntity::getProjectId, projectId);

        if (Objects.nonNull(pid)) {
            List<Long> allChildIdByPid = getAllChildIdByPid(pid, projectId);
            if (CollectionUtils.isEmpty(allChildIdByPid)) {
                PageResult<ThemeDomain> themeDomainPageResult = new PageResult<>();
                return themeDomainPageResult;
            } else {
                wrapper.in(ThemeEntity::getId, allChildIdByPid);
            }
        }
        if (StringUtils.isNotEmpty(listThemeParam.getThemeName())) {
            wrapper.like(ThemeEntity::getThemeName, listThemeParam.getThemeName());
        }
        LambdaQueryWrapper<ThemeEntity> query = wrapper.orderByDesc(ThemeEntity::getCreateTime);

        Page<ThemeEntity> page =
            this.page(new Page<>(listThemeParam.getPageNum(), listThemeParam.getPageSize()), query);
        PageResult<ThemeEntity> themeEntityPageResult =
            new PageResult<>(
                page.getTotal(),
                page.getRecords(),
                listThemeParam.getPageNum(),
                listThemeParam.getPageSize());

        List<String> creatorIdList =
            themeEntityPageResult.getResult().stream()
                .map(ThemeEntity::getCreatorId)
                .collect(Collectors.toList());

        Map<String, String> mapByUserIds = userService.getMapByUserIds(creatorIdList);

        List<ThemeDomain> resultDomainList = Lists.newArrayList();
        themeEntityPageResult
            .getResult()
            .forEach(
                themeEntity -> {
                    ThemeDomain themeDomain = themeDomainMapper.map(themeEntity);
                    themeDomain.setCreatorName(mapByUserIds.get(themeEntity.getCreatorId()));
                    resultDomainList.add(themeDomain);
                });

        PageResult<ThemeDomain> themeDomainPageResult = new PageResult<>();
        themeDomainPageResult.setResult(resultDomainList);
        themeDomainPageResult.setPageNum(themeEntityPageResult.getPageNum());
        themeDomainPageResult.setPageSize(themeEntityPageResult.getPageSize());
        themeDomainPageResult.setTotalPages(themeEntityPageResult.getTotalPages());
        themeDomainPageResult.setTotalElements(themeEntityPageResult.getTotalElements());
        return themeDomainPageResult;
    }

    /**
     * 模型左侧菜单 description 按pid构建主题树形结构
     *
     * @author : mingxi.xpb
     * @date : 2022/1/14 11:25
     */
    public List<ThemeDomain> treeThemesByPid(Long projectId, Long pid) {

        ThemeEntity fixedTheme = null;
        for (ThemeEntity parentTheme : INITIAL_LEVEL) {
            if (Objects.equals(parentTheme.getId(), pid)) {
                fixedTheme = parentTheme;
                break;
            }
        }
        boolean fixedThemeExist = (fixedTheme != null);

        //    Query queryThemes =
        //        new Query(Criteria.where("projectId").is(projectId))
        //            .with(Sort.by(Sort.Direction.ASC, "sort"));

        LambdaQueryWrapper<ThemeEntity> eq =
            new LambdaQueryWrapper<ThemeEntity>().eq(ThemeEntity::getProjectId, projectId);

        LambdaQueryWrapper<ThemeEntity> queryThemes = eq.orderByAsc(ThemeEntity::getSort);

        List<ThemeEntity> themeEntityList = themeMapper.selectList(queryThemes);
        Map<Long, List<ThemeEntity>> themeEntityMap = new HashMap<Long, List<ThemeEntity>>();
        for (ThemeEntity item : themeEntityList) {
            List<ThemeEntity> valueList = themeEntityMap.getOrDefault(item.getPid(), new ArrayList<>());
            valueList.add(item);
            themeEntityMap.putIfAbsent(item.getPid(), valueList);
            if (!fixedThemeExist && Objects.equals(item.getId(), pid)) {
                fixedTheme = item;
            }
        }

        if (null == fixedTheme) {
            throw new BusinessException("要展开的主题不存在");
        }

        Queue<ThemeEntity> q = new LinkedList();
        List<ThemeEntity> resultList = new ArrayList<>();
        // 把父节点放入queue
        q.add(fixedTheme);
        while (!q.isEmpty()) {
            ThemeEntity head = q.remove();
            resultList.add(head);
            if (CollectionUtils.isNotEmpty(themeEntityMap.get(head.getId()))) {
                q.addAll(themeEntityMap.get(head.getId()));
            }
        }
        return themeDomainMapper.map(resultList);
    }

    /**
     * 模型左侧菜单 description 按类型区分的主题树形结构
     *
     * @author : mingxi.xpb
     * @date : 2022/1/14 11:25
     */
    public List<ThemeDomain> treeThemes(Long projectId, String themeName) {
        ThemeEntity fixedTheme = null;
        for (ThemeEntity parentTheme : INITIAL_LEVEL) {
            if (Objects.equals(parentTheme.getThemeName(), themeName)) {
                fixedTheme = parentTheme;
                break;
            }
        }
    /*    Query queryThemes =
    new Query(Criteria.where("projectId").is(projectId))
        .with(Sort.by(Sort.Direction.ASC, "sort"));*/

        LambdaQueryWrapper<ThemeEntity> eq =
            new LambdaQueryWrapper<ThemeEntity>().eq(ThemeEntity::getProjectId, projectId);

        LambdaQueryWrapper<ThemeEntity> queryThemes = eq.orderByAsc(ThemeEntity::getSort);

        //    List<ThemeEntity> themeEntityList = themeMapper.findMulti(queryThemes);

        List<ThemeEntity> themeEntityList = themeMapper.selectList(queryThemes);

        Map<Long, List<ThemeEntity>> themeEntityMap = new HashMap<Long, List<ThemeEntity>>();
        for (ThemeEntity item : themeEntityList) {
            List<ThemeEntity> valueList = themeEntityMap.getOrDefault(item.getPid(), new ArrayList<>());
            valueList.add(item);
            themeEntityMap.putIfAbsent(item.getPid(), valueList);
        }
        Queue<ThemeEntity> q = new LinkedList();
        List<ThemeEntity> resultList = new ArrayList<>();
        // themeEntity目前没有type,没法直接查出一级主题下所有主题
        q.add(fixedTheme);
        while (!q.isEmpty()) {
            ThemeEntity head = q.remove();
            if (Objects.nonNull(head)) {
                resultList.add(head);
                List<ThemeEntity> themeEntities = themeEntityMap.get(head.getId());
                if (CollectionUtils.isNotEmpty(themeEntities)) {
                    q.addAll(themeEntityMap.get(head.getId()));
                }
            }
        }
        return themeDomainMapper.map(resultList);
    }

    /**
     * description 主题树形结构
     *
     * @author : mingxi.xpb
     * @date : 2022/1/14 11:25
     */
    public List<ThemeDomain> getThemesByProjectId(Long projectId) {
        List<ThemeEntity> treeThemes = new ArrayList<>(INITIAL_LEVEL);
    /*    Query queryThemes =
    new Query(Criteria.where("projectId").is(projectId))
        .with(Sort.by(Sort.Direction.ASC, "sort"));*/

        LambdaQueryWrapper<ThemeEntity> eq =
            new LambdaQueryWrapper<ThemeEntity>().eq(ThemeEntity::getProjectId, projectId);
        eq.orderByAsc(ThemeEntity::getSort);
        treeThemes.addAll(themeMapper.selectList(eq));
        return themeDomainMapper.map(treeThemes);
    }

    public ThemeDomain getThemeByThemeName(Long projectId, String themeName) {
        List<ThemeDomain> themeDomainList = treeThemes(projectId, "公共层");
        List<ThemeDomain> collect =
            themeDomainList.stream()
                .filter(Objects::nonNull)
                .filter(e -> e.getThemeName().equals(themeName))
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(collect)) {
            return null;
        }
        return collect.get(0);
    }

    /**
     * description 更改主题顺序 （不再支持）
     *
     * @author : mingxi.xpb
     * @date : 2022/1/14 11:25
     */
    public void moveTheme(MoveThemeParam moveThemeParam, Long projectId) {
        ThemeEntity moveThemeEntity = themeMapper.selectById(moveThemeParam.getMoveThemeId());
        ThemeEntity targetThemeEntity = themeMapper.selectById(moveThemeParam.getTargetThemeId());

        Integer targetSort = targetThemeEntity.getSort();
        if (!moveThemeEntity.getPid().equals(targetThemeEntity.getPid())) {
            throw new BusinessException("仅支持在同级主题移动顺序");
        }

        if (moveThemeParam.getDirection().equals(1)) { // 向上移动
            moveThemeEntity.setSort(targetSort);
            targetThemeEntity.setSort(targetSort + 1);
        } else { // 向下移动
            moveThemeEntity.setSort(targetSort + 1);
        }

        LambdaQueryWrapper<ThemeEntity> gt =
            new LambdaQueryWrapper<ThemeEntity>()
                .eq(ThemeEntity::getProjectId, projectId)
                .eq(ThemeEntity::getPid, moveThemeEntity.getPid())
                .gt(ThemeEntity::getSort, targetSort);

        // themeMapper.update(gt);

        //        themeMapper.update(
        //                new Query(
        //                        Criteria.where("projectId")
        //                                .is(projectId)
        //                                .and("pid")
        //                                .is(moveThemeEntity.getPid())
        //                                .and("sort")
        //                                .gt(targetSort)),
        //
        //                new Update().inc("sort", 1));
        //
        //
        //        themeMapper.updateByIdSelective(moveThemeEntity);
        //        themeMapper.updateByIdSelective(targetThemeEntity);
    }

    /**
     * description: 同级主题不能同名，同一个层级下的顶级主题不同名
     *
     * @author : mingxi.xpb
     * @date : 2022/1/7 14:21
     */
    private void isThemeNameExist(Long themeId, Long pid, String themeName, Long projectId) {
        ThemeEntity byId = themeMapper.selectById(pid);

        /** 查询在同一个工作空间下，同一个pid下，是否有同名主题 */
        LambdaQueryWrapper<ThemeEntity> queryWrapper =
            new LambdaQueryWrapper<ThemeEntity>()
                .eq(ThemeEntity::getPid, pid)
                .eq(ThemeEntity::getProjectId, projectId)
                .eq(ThemeEntity::getThemeName, themeName);

        ThemeEntity one = this.getOne(queryWrapper);
        /** 编辑状态 */
        if (themeId != null) {
            /** 允许编辑时，主题名不变 */
            if (one == null || one.getId().equals(themeId)) {
                return;
            } else if (0L == byId.getPid()) {
                throw new BusinessException("该层级下已存在同名主题");
            } else {
                throw new BusinessException("同一主题下不能存在相同的主题名");
            }
            /** 新增状态 */
        } else {
            if (one == null) {
                return;
            } else if (0L == byId.getPid()) {
                throw new BusinessException("该层级下已存在同名主题");
            } else {
                throw new BusinessException("同一主题下不能存在相同的主题名");
            }
        }
    }

    /**
     * description: 获得默认的主题数据
     *
     * @author : mingxi.xpb
     * @date : 2022/1/7 13:43
     */
    @PostConstruct
    private void getInitialData() {

        LambdaQueryWrapper<ThemeEntity> wrapper =
            new LambdaQueryWrapper<ThemeEntity>()
                .ne(ThemeEntity::getPid, 0L)
                .isNull(ThemeEntity::getProjectId);

        List<ThemeEntity> defaultThemes = this.list(wrapper);

        defaultThemes.forEach(e -> e.setId(null)); // id字段为null可以保证复制的主题插入到新的工作空间后可以使id字段为mongoDB自己生成的id

        INITIAL_THEMES.addAll(defaultThemes);

        List<ThemeEntity> defaultThemeLevel =
            // Criteria.where("pid").is("0")
            themeMapper.selectList(new LambdaQueryWrapper<ThemeEntity>().eq(ThemeEntity::getPid, 0L));
        INITIAL_LEVEL.addAll(defaultThemeLevel);
    }

    /**
     * description: 为新建的工作空间灌入默认主题，工作空间创建好后调用
     *
     * @author : mingxi.xpb
     * @date : 2022/1/7 14:09
     */
    public void insertInitialThemes(Long projectId, String userId) {
        List<ThemeEntity> initThemes = new ArrayList<>(INITIAL_THEMES);
        initThemes.forEach(
            e -> {
                e.setProjectId(projectId);
                e.setCreatorId(userId);
                e.setUpdaterId(userId);
            });

        this.saveBatch(initThemes);
    }

    /**
     * 获取一级主题
     *
     * @param
     * @return
     */
    public List<ThemeDomain> getPrimaryThemes() {
        //    Query query = new Query(Criteria.where("pid").is("0"));

        LambdaQueryWrapper<ThemeEntity> query =
            new LambdaQueryWrapper<ThemeEntity>().eq(ThemeEntity::getPid, 0);

        List<ThemeEntity> multi = themeMapper.selectList(query);
        List<ThemeDomain> themeDomains = themeDomainMapper.map(multi);
        return themeDomains;
    }

    public ThemeEntity getThemeIfNotExistCreate(Long projectId, String name, Long pid) {
    /*Query query =
    new Query(
        Criteria.where("projectId").is(projectId).and("pid").is(pid).and("themeName").is(name));*/

        LambdaQueryWrapper<ThemeEntity> query =
            new LambdaQueryWrapper<ThemeEntity>()
                .eq(ThemeEntity::getPid, pid)
                .eq(ThemeEntity::getProjectId, projectId)
                .eq(ThemeEntity::getThemeName, name);

        ThemeEntity one = this.getOne(query, false);
        if (Objects.isNull(one)) {
            ThemeEntity themeEntity = new ThemeEntity();
            themeEntity.setPid(pid);
            themeEntity.setProjectId(projectId);
            themeEntity.setThemeName(name);
            themeEntity.setCreateTime(new Date());
            themeEntity.setCreatorId(UserContext.getUserId());
            themeEntity.setUpdateTime(new Date());
            themeMapper.insert(themeEntity);
            return themeEntity;
        }
        return one;
    }

    public ThemeDomain getThemeById(Long id) {
        ThemeEntity byId = themeMapper.selectById(id);
        ThemeDomain themeDomain = themeDomainMapper.map(byId);
        return themeDomain;
    }

    /**
     * 通过ids获取主题域信息
     *
     * @param ids
     * @return
     */
    public Map<Long, ThemeDomain> getMapByIds(List<Long> ids) {
        ids = ids.stream().distinct().collect(Collectors.toList());
        //    Query query = new Query(Criteria.where("id").in(ids));

        if (CollectionUtils.isEmpty(ids)) {
            return Collections.EMPTY_MAP;
        }
        LambdaQueryWrapper<ThemeEntity> query =
            new LambdaQueryWrapper<ThemeEntity>().in(ThemeEntity::getId, ids);
        List<ThemeDomain> themeDomains = themeDomainMapper.map(themeMapper.selectList(query));
        return themeDomains.stream()
            .collect(Collectors.toMap(ThemeDomain::getId, themeDomain -> themeDomain));
    }

    /**
     * description 主题层级能不超过5层
     *
     * @author : mingxi.xpb
     * @date : 2022/2/16 17:41
     */
    private boolean validateLevels(Long themeId) {
        ThemeDomain themeDomain = getThemeById(themeId);
        ArrayList<Object> arrayList = Lists.newArrayList();
        arrayList.add(themeDomain.getThemeName());

        while (true) {
            Long themePid = themeDomain.getPid();
            themeDomain = getThemeById(themePid);
            if (themeDomain == null || (0L == themeDomain.getPid())) {
                break;
            }
            arrayList.add(themeDomain.getThemeName());
        }

        if (arrayList.size() < 5) {
            return true;
        }
        return false;
    }

    /**
     * 通过id查询所有的子id
     */
    public List<Long> getAllChildIdByPid(Long id, Long projectId) {

        LambdaQueryWrapper<ThemeEntity> eq =
            new LambdaQueryWrapper<ThemeEntity>().eq(ThemeEntity::getProjectId, projectId);

        List<ThemeEntity> multi = themeMapper.selectList(eq);
        Map<Long, List<ThemeEntity>> collect =
            multi.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(ThemeEntity::getPid));

        Map<Long, List<Long>> r2 = Maps.newHashMap();
        collect.forEach(
            (k, v) -> {
                List<Long> v2 = v.stream().map(e -> e.getId()).collect(Collectors.toList());
                r2.put(k, v2);
            });
        List<Long> res = Lists.newArrayList();

        ThemeEntity byId = themeMapper.selectById(id);
        if (byId == null) {
            return res;
        }
        if (0L != byId.getPid()) {
            res.add(id);
        }
        doSearchAllThemeChild(r2, id, res);
        return res;
    }

    public static List<Long> doSearchAllThemeChild(
        Map<Long, List<Long>> r2, Long id, List<Long> res) {
        if (Objects.nonNull(id)) {
            List<Long> strings = r2.get(id);
            if (CollectionUtils.isNotEmpty(strings)) {
                for (Long k1 : strings) {
                    res.add(k1);
                    if (r2.containsKey(k1)) {
                        doSearchAllThemeChild(r2, k1, res);
                    }
                }
            }
        }
        return res;
    }

    /**
     * description 根据主题id将主题名包括其所有父级主题名串接起来
     *
     * @author : mingxi.xpb
     * @date : 2022/2/10 15:44
     */
    public String spliceThemeNameByThemeId(Long themeId) {
        if (themeId == null) {
            return null;
        }
        ThemeDomain themeDomain = getThemeById(themeId);
        StringBuilder builder = new StringBuilder();
        Stack<String> stack = new Stack<>();
        stack.push(themeDomain.getThemeName());

        while (true) {
            Long themePid = themeDomain.getPid();
            themeDomain = getThemeById(themePid);
            if (themeDomain == null) {
                break;
            }
            stack.push(themeDomain.getThemeName());
        }

        while (!stack.isEmpty()) {
            builder.append(stack.pop()).append("/");
        }
        builder.deleteCharAt(builder.length() - 1);

        return builder.toString();
    }

    public List<ThemeDomain> getListByPage(Long projectId, Integer pageSize, Integer pageNum) {

        Page<ThemeEntity> page =
            this.page(
                new Page<>(pageNum, pageSize),
                new LambdaQueryWrapper<ThemeEntity>().eq(ThemeEntity::getProjectId, projectId));

        final List<ThemeDomain> themeDomains = themeDomainMapper.map(page.getRecords());
        return themeDomains;
    }
}
